package com.founder.gateway.system.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.dom4j.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.founder.gateway.system.util.HttpNormUtil.HEADER_FOUNDER;

public class SOAPUtil {
    public static final String HEADER_ENVELOPE_XMLNS = HEADER_FOUNDER + "soap.envelope.xmlns";
    public static final String HEADER_ENVELOPE_ATTR = HEADER_FOUNDER + "soap.envelope.attr";

    public static final String HEADER_ACTION_XMLNS = HEADER_FOUNDER + "soap.action.xmlns";
    public static final String HEADER_ACTION_ATTR = HEADER_FOUNDER + "soap.action.attr";

    public static final String HEADER_PROTOCOL = HEADER_FOUNDER + "soap.protocol";

    public static final String SOAP_PROTOCOL_1_1 = "soap1.1";
    public static final String SOAP_PROTOCOL_1_2 = "soap1.2";

    public static String getContentType(String protocol) {
        return (SOAP_PROTOCOL_1_2.equalsIgnoreCase(protocol) ? "application/soap+xml" : "text/xml") + HttpNormUtil.APPEND_UTF_8;
    }

    /**
     * 创建基础SOAP报文
     */
    public static Document createSOAPMessage(String protocol) {
        Element root = DocumentHelper.createElement(new QName("Envelope", new Namespace("soap",
                SOAP_PROTOCOL_1_2.equalsIgnoreCase(protocol) ?
                        "http://schemas.xmlsoap.org/soap/envelope/" :
                        "http://www.w3.org/2003/05/soap-envelope"
        )));
        root.addElement(new QName("Header", root.getNamespace()));
        root.addElement(new QName("Body", root.getNamespace()));
        Document document = DocumentHelper.createDocument(root);
        document.setXMLEncoding("utf-8");
        return document;
    }

    /**
     * 向指定节点添加命名空间
     * 格式：prefix|uri
     * 例：
     * |http://test    将添加 xmlns="http://test"
     * xs|http://test  将添加 xmlns:xs="http://test"
     */
    public static void addXmlns(Element node, List<String> list) {
        if (list == null) {
            return;
        }
        list.stream().filter(Objects::nonNull).forEach(s -> {
            String[] data = s.split("\\|", 2);
            if (data.length == 2) {
                String prefix = data[0];
                String uri = data[1];
                if (prefix.isEmpty()) {
                    node.setQName(new QName("X", new Namespace(prefix, uri), node.getQualifiedName()));
                } else {
                    node.addNamespace(prefix, uri);
                }
            }
        });
    }

    /**
     * 向指定节点添加属性
     * 格式：name|value
     * 例：
     * title|tom       将添加 title="tom"
     * soap:code|123   将添加 soap:code="123"
     */
    public static void addAttr(Element node, List<String> list) {
        if (list == null) {
            return;
        }
        list.stream().filter(Objects::nonNull).forEach(s -> {
            String[] data = s.split("\\|", 2);
            if (data.length == 2) {
                node.addAttribute(data[0], data[1]);
            }
        });
    }

    /**
     * json 转 xml
     * norm ：是否保留 namespace、attribute、prefix
     */
    public static void json2xml(JSONObject json, Element node, boolean norm) {
        json.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(entry -> {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value instanceof JSONObject) {
                Element element = DocumentHelper.createElement(new QName("X", node.getNamespace(), key));
                node.add(element);
                json2xml((JSONObject) value, element, norm);
            } else if (value instanceof JSONArray) {
                for (Object object : (JSONArray) value) {
                    if (object instanceof JSONObject) {
                        Element element = DocumentHelper.createElement(new QName("X", node.getNamespace(), key));
                        node.add(element);
                        json2xml((JSONObject) object, element, norm);
                    } else {
                        Element element = DocumentHelper.createElement(new QName("X", node.getNamespace(), key));
                        element.setText(object == null ? "" : object.toString());
                        node.add(element);
                    }
                }
            } else {
                String text = value == null ? "" : value.toString();
                if (norm) {
                    if (key.startsWith("-")) {
                        if (key.length() == 1) {
                            node.setQName(new QName("X", new Namespace(key.substring(1), text), node.getQualifiedName()));
                        } else {
                            node.addNamespace(key.substring(1), text);
                        }
                    } else if (key.startsWith(".")) {
                        node.addAttribute(key.substring(1), text);
                    } else if (key.isEmpty()) {
                        node.setText(text);
                    } else {
                        Element element = DocumentHelper.createElement(new QName("X", node.getNamespace(), key));
                        element.setText(text);
                        node.add(element);
                    }
                } else {
                    Element element = DocumentHelper.createElement(new QName("X", node.getNamespace(), key));
                    element.setText(text);
                    node.add(element);
                }
            }
        });
    }

    /**
     * xml 转 json
     * norm ：是否保留 namespace、attribute、prefix
     */
    public static void xml2json(Element node, JSONObject json, boolean norm) {
        String name = node.getName();
        Map<String, Object> map = new HashMap<>();
        if (norm) {
            name = node.getQualifiedName();
            for (Namespace namespace : node.declaredNamespaces()) {
                map.put("-" + namespace.getPrefix(), namespace.getURI());
            }
            for (Attribute attribute : node.attributes()) {
                map.put("." + attribute.getQualifiedName(), attribute.getValue());
            }
        }
        if (json.containsKey(name)) {
            Object object = json.get(name);
            JSONArray array;
            if (object instanceof JSONArray) {
                array = (JSONArray) object;
            } else {
                array = new JSONArray();
                array.add(object);
            }
            List<Element> list = node.elements();
            if (list.isEmpty()) {
                if (map.isEmpty()) {
                    array.add(node.getTextTrim());
                } else {
                    JSONObject newJson = new JSONObject(map);
                    newJson.put("", node.getTextTrim());
                    array.add(newJson);
                }
            } else {
                JSONObject newJson = new JSONObject(map);
                for (Element e : list) {
                    xml2json(e, newJson, norm);
                }
                array.add(newJson);
            }
            json.put(name, array);
        } else {
            List<Element> list = node.elements();
            if (list.isEmpty()) {
                if (map.isEmpty()) {
                    json.put(name, node.getTextTrim());
                } else {
                    JSONObject newJson = new JSONObject(map);
                    newJson.put("", node.getTextTrim());
                    json.put(name, newJson);
                }
            } else {
                JSONObject newJson = new JSONObject(map);
                for (Element e : list) {
                    xml2json(e, newJson, norm);
                }
                json.put(name, newJson);
            }
        }
    }
}
